#include "tx.h"
#include "globalParameters.h"
#include <iostream>
#include <cstdlib>
#include <cmath>
#include <ctime>

using namespace std;

Tx::Tx(int id, int x, int y, double power, GlobalParameters parameters)
{
	srand(time(0));

	txID = id;
	xPos = x,
	yPos = y;
	active = false;
	txPower = power;
	currentCW = parameters.getCwMin();
	successfulPackets = 0;
	failedPackets = 0;
	rounds = 0;
	active = 0;
	interference = 0.0;
	noise = pow(10.0,-13.0);//noise level accross the network
	timeToFire = parameters.getDIFS() + (rand() % currentCW)*parameters.getSlotTime();
	slotsToGo = -1;
	transmitValue = false;
	queueSize = 0;
	timeWaiting = 0;
}

void Tx::print(){
	cout << "TX ID: " << txID << endl;
	//cout << "xPos: " << xPos << endl;
	//cout << "yPos: " << yPos << endl;
	//cout << "power: " << txPower << endl;
	//cout << "currentCW: " << currentCW << endl;
	//cout << "Time to fire: " << timeToFire << endl;
	cout << "Queue Size: " << queueSize << endl;
	cout << "Successful packets: "<< successfulPackets << endl;
	cout << "Failed packets: " << failedPackets << endl << endl;
}

void Tx::setCurrentCW(int cw){
	currentCW = cw;
}

int Tx::getCurrentCW()
{
	return currentCW;
}

void Tx::setSuccessfulPackets(int sp){
	successfulPackets = sp;
}

int Tx::getSuccessfulPackets(){
	return successfulPackets;
}

void Tx::setFailedPackets(int fp){
	failedPackets = fp;
}

int Tx::getFailedPackets(){
	return failedPackets;
}

void Tx::setTimeToFire(int ttf){
	timeToFire = ttf;
}

int Tx::getTimeToFire(){
	return timeToFire;
}

void Tx::setRounds(int inputRounds){
	rounds = inputRounds;
}

int Tx::getRounds(){
	return rounds;
}

void Tx::setActive(bool inputActive){
	active = inputActive;
}

bool Tx::getActive(){
	return active;
}

void Tx::setReceiver(int inputRec){
	receiver = inputRec;
}

int Tx::getReceiver(){
	return receiver;
}

int Tx::getX(){
	return xPos;
}

int Tx::getY(){
	return yPos;
}

double Tx::getPower(){
	return txPower;
}

int Tx::getId(){
	return txID;
}

void Tx::incrementInterference(double addValue){
	interference = interference + addValue;
}

bool Tx::canTransmit(GlobalParameters parameters){
	if(interference < parameters.getCsThreshold()){ 
		
	return true;
	}
	return false;
	
}

double Tx::getInterference()
{
	return interference;
}

void Tx::setInterference(double i)
{
	if (i<0) {
		cout <<"wrong interference value";
		return;
	}
	
 	interference = i;
}

double Tx::getNoise()
{
	return noise;
}

void Tx::setNoise(double n){
	if (n < 0) 
	{
		cout << "wrong noise value";
		return;
	}
	
	noise = n;
}

void Tx::setSlotsToGo(int input){
	slotsToGo = input;
}

int Tx::getSlotsToGo(){
	return slotsToGo;
}

void Tx::decrementSlotsToGo(){
	slotsToGo = slotsToGo - 1;
}

void Tx::setCwOnFail(int protocol,GlobalParameters parameters){
	int newVal = currentCW;
	
	//EI
	if(protocol==1){
		newVal = 2*currentCW;
	}
	//Log-log iterated
	if(protocol==2){
		int loglogvalue = ceil(log2(log2(currentCW)));
		if(rounds>=loglogvalue){
			rounds = 0;
			newVal = 2*currentCW;
		}
	}
	
	//EI with nodes estimated min
	if(protocol==3){
		newVal = 2*currentCW;
	}
	
	currentCW = newVal;
	//check to see cwvalue doesn't exceed max value
	if(currentCW>parameters.getCwMax()){
		currentCW = parameters.getCwMax();
	}

}

void Tx::setCwOnSuccess(int protocol,GlobalParameters parameters,int numNodes){
	
	if(protocol==1){
		currentCW = parameters.getCwMin();
	}
	if(protocol==2){
		currentCW = parameters.getCwMin();
	}
	
	if(protocol==3){
		currentCW = numNodes*numNodes*ceil(log2(numNodes));
		if(currentCW<=parameters.getCwMin()){
			currentCW = parameters.getCwMin();
		}
	}


}

void Tx::incrementRounds(){
	rounds = rounds+1;
}

void Tx::updateTimeToFire(GlobalParameters parameters){
timeToFire = parameters.getDIFS() + (rand() % currentCW);
}

void Tx::incrementSuccessfulPackets(){
	successfulPackets = successfulPackets+1;
}

void Tx::incrementFailedPackets(){
	failedPackets = failedPackets+1;
}

void Tx::decreaseTimeToFire(double change){
	timeToFire = timeToFire - change;
}

bool Tx::hasTransmitted(){
	return transmitValue;
}

void Tx::setTransmitValue(bool input){
	transmitValue = input;
}

void Tx::setSlotsToGoOnFail(){
	//srand(time(0));
	slotsToGo = 1+(rand()% currentCW);
	//cout << slotsToGo << ',';
}

void Tx::setSlotsToGoOnStart(){
	srand(time(0));
	slotsToGo = 1+(rand()% currentCW);
	//cout << slotsToGo << ',';
}

int Tx::getQueueSize(){
	return queueSize;
}

void Tx::setQueueSize(int input){
	queueSize = input;
}

void Tx::incrementQueueSize(){
	queueSize++;
}

void Tx::decrementQueueSize(){
	queueSize--;
}

int Tx::getTimeWaiting(){
	return timeWaiting;
}

void Tx::setTimeWaiting(int input){
	timeWaiting = input;
}

void Tx::checkForMorePackets(double lambda,GlobalParameters parameters){
	
	//timeWaiting = timeWaiting+ parameters.getSlotTime();
	double poissonValue = pow(2.71828182845904523536,-lambda) * lambda;
	double coinFlip = (1.0 * (rand()%101))/100.0;
	if(coinFlip < poissonValue){
		incrementQueueSize();
	}
	
	
	
}
